
package com.jf.cloud.im.socket.platform;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.bo.UserInfoInTokenBO;
import com.jf.cloud.api.auth.feign.TokenFeignClient;
import com.jf.cloud.api.platform.feign.SysUserClient;
import com.jf.cloud.api.platform.vo.SysUserVO;
import com.jf.cloud.api.user.feign.UserFeignClient;
import com.jf.cloud.api.user.vo.UserApiVO;
import com.jf.cloud.common.cache.util.RedisUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Json;
import com.jf.cloud.im.constants.Constant;
import com.jf.cloud.im.constants.MsgCode;
import com.jf.cloud.im.constants.SendType;
import com.jf.cloud.im.model.ImMsgBizUserHistory;
import com.jf.cloud.im.service.ImMsgBizUserHistoryService;
import com.jf.cloud.im.socket.app.UserOnlineWebSocketServer;
import com.jf.cloud.im.socket.app.UserWebSocketServer;
import com.jf.cloud.im.vo.MessageInfoVO;
import com.jf.cloud.im.vo.MsgItemVO;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 平台收到的消息
 * 10,"无法获取用户信息"
 * 11,"账户已在别处登录，请刷新"
 * 12,"对方不在线"
 * 13, "内容格式有误"
 *
 * @author zz
 */
@ServerEndpoint("/p/ua/im/websocket/{token}/{userId}")
@Component
public class SysWebSocketServer {

    /**
     * userId为key
     */
    public static final ConcurrentHashMap<String, Session> SYS_MAP = new ConcurrentHashMap<>(256);

    private static TokenFeignClient tokenFeignClient;

    private static SysUserClient sysUserClient;

    private static UserFeignClient userFeignClient;

    private static ImMsgBizUserHistoryService imMsgBizUserHistoryService;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        tokenFeignClient = applicationContext.getBean(TokenFeignClient.class);
        sysUserClient = applicationContext.getBean(SysUserClient.class);
        userFeignClient = applicationContext.getBean(UserFeignClient.class);
        imMsgBizUserHistoryService = applicationContext.getBean(ImMsgBizUserHistoryService.class);
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        token = Base64.decodeStr(token);
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient.checkToken(token);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            throw new LuckException(userInfoInTokenVoServerResponseEntity.getMsg());
        }
        UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();
        if (userInfoInToken == null) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        // 如果原来就有token
        Session oldSession = SYS_MAP.get(Constant.SYS_PREFIX + userInfoInToken.getUserId());
        if (oldSession != null) {
            // 客户端收到11，关闭ws链接，弹出提示
            if (oldSession.isOpen()) {
                oldSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(11, "账户已在别处登录，请刷新")));
                oldSession.close();
            }
        }

        SYS_MAP.put(Constant.SYS_PREFIX + userInfoInToken.getUserId(), session);
        RedisUtil.set(Constant.SYS_PREFIX + userInfoInToken.getUserId(), "", 0);
        if (session.isOpen()) {
            session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success("ok")));
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("token") String token, @PathParam(value = "userId") Long userId) {
        SYS_MAP.remove(Constant.SYS_PREFIX + userId);
        RedisUtil.del(Constant.SYS_PREFIX + userId);
    }

    /**
     * 连接错误调用的方法
     */
    @OnError
    public void onError(Session session, @PathParam("token") String token, Throwable error, @PathParam(value = "userId") Long userId) {
        SYS_MAP.remove(Constant.SYS_PREFIX + userId);
        RedisUtil.del(Constant.SYS_PREFIX + userId);
    }

    /**
     * 收到客户端消息后调用的方法，该消息由用户发过来
     *
     * @param sourceMessage 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String sourceMessage, @PathParam("token") String token, Session session) throws IOException {
        token = Base64.decodeStr(token);
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient.checkToken(token);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            throw new LuckException(userInfoInTokenVoServerResponseEntity.getMsg());
        }
        UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();
        if (Objects.isNull(userInfoInToken)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }

        if (StrUtil.isBlank(sourceMessage)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        MessageInfoVO messageInfo = Json.parseObject(sourceMessage, MessageInfoVO.class);

        if (Objects.isNull(messageInfo)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CONTENT_FORMAT_ERROR, "内容格式有误")));
            }
            return;
        }

        // 保持心跳
        if (StrUtil.equals(messageInfo.getContent(), Constant.HEART_BEAT)) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HEART_BEAT, "保持心跳")));
            }
            return;
        }

        Long userId = messageInfo.getToId();
        ServerResponseEntity<UserApiVO> userApiResponse = userFeignClient.getInsiderUserData(userId);
        if (!userApiResponse.isSuccess()) {
            throw new LuckException(userApiResponse.getMsg());
        }
        UserApiVO user = userApiResponse.getData();
        if (Objects.isNull(user)) {
            user = new UserApiVO();
            user.setUserId(userId);
            user.setUserName("*用户已注销*");
            user.setNickName("*用户已注销*");
        }

        sendToUser(messageInfo, userInfoInToken, user, session);
    }

    public void sendToUser(MessageInfoVO messageInfo, UserInfoInTokenBO userInfoInToken, UserApiVO user, Session session) throws IOException {
        ServerResponseEntity<SysUserVO> sysUserResponse2 = sysUserClient.getSysUserByUserId(userInfoInToken.getUserId());
        if (!sysUserResponse2.isSuccess()) {
            throw new LuckException(sysUserResponse2.getMsg());
        }
        SysUserVO sysUser2 = sysUserResponse2.getData();

        // 获取消息历史
        if (Objects.nonNull(messageInfo.getHistory()) && Objects.equals(messageInfo.getHistory(), true)) {
            PageVO<MsgItemVO> msgItemPage = imMsgBizUserHistoryService.getPlatformUserHistory(userInfoInToken, messageInfo, user, sysUser2);
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.HISTORY, msgItemPage)));
            }
            return;
        }

        // 标记消息已读
        if (Objects.nonNull(messageInfo.getRead()) && Objects.equals(messageInfo.getRead(), true)) {
            if (Objects.nonNull(messageInfo.getMsgIds()) && !messageInfo.getMsgIds().isEmpty()) {
                List<ImMsgBizUserHistory> imMsgBizUserHistories = imMsgBizUserHistoryService.markPlatformUserRead(messageInfo, userInfoInToken, user.getUserId());
                if (!imMsgBizUserHistories.isEmpty()) {
                    if (session.isOpen()) {
                        session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, "ok")));
                    }
                    Session userSession = UserWebSocketServer.USER_MAP.get(Constant.USER_PREFIX + messageInfo.getToId());
                    if (Objects.nonNull(userSession)) {
                        if (userSession.isOpen()) {
                            userSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.READ, messageInfo.getMsgIds())));
                        }
                    }
                }
            }
            return;
        }

        if (Objects.nonNull(messageInfo.getOnlineOrOffline()) && Objects.equals(messageInfo.getOnlineOrOffline(), true)) {
            Set<String> set = RedisUtil.keys(Constant.ONLINE_USER_PREFIX + user.getUserId() + Constant.UNDERLINE + "*");
            MsgItemVO msgItem = new MsgItemVO();
            msgItem.setChatType(SendType.PLATFORM);
            msgItem.setUserId(user.getUserId());
            if (!set.isEmpty()) {
                msgItem.setOnlineOrOffline(true);
            } else {
                msgItem.setOnlineOrOffline(false);
            }
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.ONLINE_OR_OFFLINE, msgItem)));
            }
        }

        String tempString = RedisUtil.get(Constant.IN_CHARGE_SYS + messageInfo.getToId());
        Long sysUserId = null;
        if (Objects.nonNull(tempString)) {
            sysUserId = Long.valueOf(tempString.substring(4));
            if (Objects.nonNull(sysUserId)) {
                SysUserVO userVO = sysUserClient.getSysUserByUserId(sysUserId).getData();
                if (userVO == null) {
                    // 负责客户的客服不存在，删除缓存
                    RedisUtil.del(Constant.IN_CHARGE_SYS + messageInfo.getToId());
                } else if (!Objects.equals(sysUserId, userInfoInToken.getUserId())) {
                    if (session.isOpen()) {
                        session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(15, "不是你负责的客户")));
                    }
                    return;
                }
            }
        }

        // 用户注销后不可以进行后面的操作
        if (Objects.isNull(user.getStatus())) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.fail(MsgCode.CAN_NOT_FIND_USER_INFO, "无法获取用户信息")));
            }
            return;
        }
        // 获取可转接客服列表
        if (Objects.nonNull(messageInfo.getPlatformUserList()) && Objects.equals(messageInfo.getPlatformUserList(), true)) {
            Set<String> set = RedisUtil.keys(Constant.SYS_PREFIX + "*");
            List<SysUserVO> listSysUser = new ArrayList<>();
            for (String key : set) {
                if (key.startsWith(Constant.SYS_PREFIX)) {
                    if (!Objects.equals(Constant.SYS_PREFIX + userInfoInToken.getUserId(), key)) {
                        long tempLength = (Constant.SYS_PREFIX).length();
                        Long tempSysUserId = Long.valueOf(key.substring((int) tempLength));
                        ServerResponseEntity<SysUserVO> sysUserResponse3 = sysUserClient.getSysUserByUserId(tempSysUserId);
                        if (!sysUserResponse3.isSuccess()) {
                            throw new LuckException(sysUserResponse3.getMsg());
                        }
                        SysUserVO sysUser3 = sysUserResponse3.getData();
                        SysUserVO sysUser4 = new SysUserVO();
                        sysUser4.setSysUserId(sysUser3.getSysUserId());
                        sysUser4.setNickName(sysUser3.getNickName());
                        listSysUser.add(sysUser4);
                    }
                }
            }
            if (session.isOpen()) {
                session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.EMPLOYEE_ONLINE, listSysUser)));
            }
            return;
        }

        // 转接客服
        if (Objects.nonNull(messageInfo.getChangeTo()) && Objects.equals(messageInfo.getChangeTo(), true)) {
            if (Objects.nonNull(messageInfo.getPlatformUserId())) {
                Session userSession = UserWebSocketServer.USER_MAP.get(Constant.USER_PREFIX + messageInfo.getToId());
                Session sysSession = SYS_MAP.get(Constant.SYS_PREFIX + messageInfo.getPlatformUserId());
                if (Objects.nonNull(sysSession)) {
                    RedisUtil.set(Constant.IN_CHARGE_SYS + messageInfo.getToId(), "test" + messageInfo.getPlatformUserId(), 0);
                    ServerResponseEntity<SysUserVO> sysUserResponse3 = sysUserClient.getSysUserByUserId(messageInfo.getPlatformUserId());
                    if (!sysUserResponse3.isSuccess()) {
                        throw new LuckException(sysUserResponse3.getMsg());
                    }
                    SysUserVO sysUser3 = sysUserResponse3.getData();
                    ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.savePlatformChangeEmployeeReply(userInfoInToken, sysUser3, user);                    imMsgBizUserHistory.setNickName(sysUser3.getNickName());
                    MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
                    if (session.isOpen()) {
                        session.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.CHANGE_EMPLOYEE_SUCCESS, msgItem)));
                    }
                    // 在线的话发送消息，不在线的话留言
                    if (Objects.nonNull(userSession) && userSession.isOpen()) {
                        userSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.CHANGE_EMPLOYEE_SUCCESS, msgItem)));
                    }
                    if (sysSession.isOpen()) {
                        sysSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(MsgCode.CHANGE_EMPLOYEE_SUCCESS, msgItem)));
                    }
                }
            }
            return;
        }

        // 发送消息
        if (Objects.nonNull(messageInfo.getContent()) && !messageInfo.getContent().isEmpty()) {
            ImMsgBizUserHistory imMsgBizUserHistory = imMsgBizUserHistoryService.savePlatformUserHistory(messageInfo, userInfoInToken);
            // 在线的话发送消息，不在线的话留言
            Session userSession = UserWebSocketServer.USER_MAP.get(Constant.USER_PREFIX + messageInfo.getToId());
            if (Objects.nonNull(userSession)) {
                if (Objects.isNull(sysUserId)) {
                    RedisUtil.set(Constant.IN_CHARGE_SYS + messageInfo.getToId(), "test" + userInfoInToken.getUserId(), 0);
                }
                imMsgBizUserHistory.setNickName(sysUser2.getNickName());
                MsgItemVO msgItem = imMsgBizUserHistoryService.getUserPlatformMsgItem(user, imMsgBizUserHistory);
                if (userSession.isOpen()) {
                    userSession.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem)));
                }
                Set<String> set2 = RedisUtil.keys(Constant.ONLINE_USER_PREFIX + messageInfo.getToId() + Constant.UNDERLINE + "*");
                List<Session> listUser2 = new ArrayList<>();
                for (String key : set2) {
                    if (key.startsWith(Constant.ONLINE_USER_PREFIX + messageInfo.getToId() + Constant.UNDERLINE)) {
                        listUser2.add(UserOnlineWebSocketServer.USER_ONLINE_MAP.get(key));
                    }
                }
                if (!listUser2.isEmpty()) {
                    MsgItemVO msgItem2 = new MsgItemVO();
                    msgItem2.setNewMessage(true);
                    for (Session userSession2 : listUser2) {
                        if (Objects.nonNull(userSession2)) {
                            if (userSession2.isOpen()) {
                                userSession2.getBasicRemote().sendText(Json.toJsonString(ServerResponseEntity.success(msgItem2)));
                            }
                        }
                    }
                }
            }
        }
    }

}
